"""
User Authentication Module
Handles user registration, login, session management, and permissions
"""
import json
import os
import secrets
import hashlib
from datetime import datetime, timedelta
from typing import Dict, Optional
from passlib.context import CryptContext


# Password hashing context
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# Directory to store user data
USERS_DIR = "users"
os.makedirs(USERS_DIR, exist_ok=True)

# Session storage
SESSIONS_FILE = os.path.join(USERS_DIR, "sessions.json")
if not os.path.exists(SESSIONS_FILE):
    with open(SESSIONS_FILE, 'w', encoding='utf-8') as f:
        json.dump({}, f)

# Users storage
USERS_FILE = os.path.join(USERS_DIR, "users.json")
if not os.path.exists(USERS_FILE):
    with open(USERS_FILE, 'w', encoding='utf-8') as f:
        json.dump({}, f)


class UserAuth:
    def __init__(self):
        self.sessions = self.load_sessions()
        self.users = self.load_users()

    def load_sessions(self) -> Dict:
        """Load active sessions from file"""
        try:
            with open(SESSIONS_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
        except FileNotFoundError:
            return {}

    def save_sessions(self):
        """Save active sessions to file"""
        with open(SESSIONS_FILE, 'w', encoding='utf-8') as f:
            json.dump(self.sessions, f, ensure_ascii=False, indent=2)

    def load_users(self) -> Dict:
        """Load users from file"""
        try:
            with open(USERS_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
        except FileNotFoundError:
            return {}

    def save_users(self):
        """Save users to file"""
        with open(USERS_FILE, 'w', encoding='utf-8') as f:
            json.dump(self.users, f, ensure_ascii=False, indent=2)

    def hash_password(self, password: str) -> str:
        """Hash a password using bcrypt"""
        return pwd_context.hash(password)

    def verify_password(self, plain_password: str, hashed_password: str) -> bool:
        """Verify a password against its hash"""
        return pwd_context.verify(plain_password, hashed_password)

    def create_user(self, username: str, password: str, email: str = None) -> bool:
        """Create a new user"""
        if username in self.users:
            return False

        hashed_password = self.hash_password(password)
        user_data = {
            "username": username,
            "email": email,
            "hashed_password": hashed_password,
            "created_at": datetime.now().isoformat(),
            "templates": []  # Store templates owned by this user
        }
        self.users[username] = user_data
        self.save_users()
        return True

    def authenticate_user(self, username: str, password: str) -> Optional[Dict]:
        """Authenticate a user and return user data if successful"""
        if username not in self.users:
            return None

        user = self.users[username]
        if self.verify_password(password, user["hashed_password"]):
            return user
        return None

    def create_session(self, username: str) -> str:
        """Create a new session for a user and return the session ID"""
        session_id = secrets.token_urlsafe(32)
        self.sessions[session_id] = {
            "username": username,
            "created_at": datetime.now().isoformat(),
            "expires_at": (datetime.now() + timedelta(hours=24)).isoformat()
        }
        self.save_sessions()
        return session_id

    def validate_session(self, session_id: str) -> Optional[str]:
        """Validate a session and return the username if valid, or None if invalid"""
        if session_id not in self.sessions:
            return None

        session = self.sessions[session_id]
        expires_at = datetime.fromisoformat(session["expires_at"])

        if datetime.now() > expires_at:
            # Session expired, remove it
            del self.sessions[session_id]
            self.save_sessions()
            return None

        return session["username"]

    def delete_session(self, session_id: str) -> bool:
        """Delete a session"""
        if session_id in self.sessions:
            del self.sessions[session_id]
            self.save_sessions()
            return True
        return False

    def get_user_templates(self, username: str) -> list:
        """Get list of templates owned by a user"""
        if username in self.users:
            return self.users[username].get("templates", [])
        return []

    def add_user_template(self, username: str, template_name: str) -> bool:
        """Add a template to a user's template list"""
        if username in self.users:
            templates = self.users[username].get("templates", [])
            if template_name not in templates:
                templates.append(template_name)
                self.users[username]["templates"] = templates
                self.save_users()
            return True
        return False

    def remove_user_template(self, username: str, template_name: str) -> bool:
        """Remove a template from a user's template list"""
        if username in self.users:
            templates = self.users[username].get("templates", [])
            if template_name in templates:
                templates.remove(template_name)
                self.users[username]["templates"] = templates
                self.save_users()
                return True
        return False

    def is_template_owned_by_user(self, username: str, template_name: str) -> bool:
        """Check if a template is owned by a specific user"""
        if username in self.users:
            templates = self.users[username].get("templates", [])
            return template_name in templates
        return False


# Global instance of UserAuth
auth = UserAuth()